#include <physics/Joint.h>

#include <physics/Node.h>
#include <physics/World.h>
#include <physics/ValueLoader.h>
#include <Box2D/Dynamics/Joints/b2Joint.h>
#include <Box2D/Dynamics/b2World.h>

namespace physics
{

Joint::Joint(World *world)
	: world(world)
	, b2joint(NULL)
{
	world->AddJoint(this);
}

Joint::~Joint()
{
	if(b2joint)
		world->b2world->DestroyJoint(b2joint);

	world->RemoveJoint(this, false);
}

bool Joint::on_attribute(xml::Provider * prov, const std::string & name, const std::string & value)
{
	if(name == "Name")
	{
		this->name = Atom(value);
		return true;
	}

	return false;
}

bool Joint::on_node(xml::Provider *prov, const std::string &name)
{
	if(name == "BodyA")
		return ValueReader::Read(prov, bodiesInfo.bodyNameA);
	if(name == "BodyB")
		return ValueReader::Read(prov, bodiesInfo.bodyNameB);
	if(name == "CollideConnected")
		return ValueReader::Read(prov, bodiesInfo.collideConnected);

	return false;
}

void Joint::CopyFrom(Joint *joint)
{
	name = joint->name;
	world = joint->world;
	bodiesInfo = joint->bodiesInfo;
}


bool Joint::Setup()
{
	Node *nodeA = bodiesInfo.bodyA == NULL ? world->FindNode(bodiesInfo.bodyNameA) : bodiesInfo.bodyA;
	if(!nodeA)
		return false;

	Node *nodeB = bodiesInfo.bodyB == NULL ? world->FindNode(bodiesInfo.bodyNameB) : bodiesInfo.bodyB;
	if(!nodeB)
		return false;

	jointDef->bodyA = nodeA->GetBody();
	jointDef->bodyB = nodeB->GetBody();
	jointDef->collideConnected = bodiesInfo.collideConnected;

	b2joint = world->b2world->CreateJoint(jointDef.get());

	return true;
}

Node * Joint::GetBodyA()
{
	return bodiesInfo.bodyA == NULL ? world->FindNode(bodiesInfo.bodyNameA) : bodiesInfo.bodyA;
}

Node * Joint::GetBodyB()
{
	return bodiesInfo.bodyB == NULL ? world->FindNode(bodiesInfo.bodyNameB) : bodiesInfo.bodyB;
}

}
